package org.yzhzc.friend.service.exam.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.yzhzc.common.core.constants.Constants;
import org.yzhzc.common.core.domain.TableDataInfo;
import org.yzhzc.common.core.utils.ThreadLocalUtil;
import org.yzhzc.friend.domain.exam.dto.ExamQueryDTO;
import org.yzhzc.friend.domain.exam.dto.ExamRankDTO;
import org.yzhzc.friend.domain.exam.vo.ExamRankVO;
import org.yzhzc.friend.domain.exam.vo.ExamVO;
import org.yzhzc.friend.domain.user.vo.UserVO;
import org.yzhzc.friend.manager.ExamCacheManager;
import org.yzhzc.friend.manager.UserCacheManager;
import org.yzhzc.friend.mapper.exam.ExamMapper;
import org.yzhzc.friend.mapper.user.UserExamMapper;
import org.yzhzc.friend.service.exam.IExamService;

import java.util.List;

/**
 * 竞赛服务实现类，负责处理竞赛相关的业务逻辑。
 * 包括竞赛列表查询、竞赛排名查询、竞赛题目导航等。
 */
@Slf4j
@Service
public class ExamServiceImpl implements IExamService {

    @Autowired
    private ExamMapper examMapper; // 竞赛数据访问接口

    @Autowired
    private ExamCacheManager examCacheManager; // 竞赛缓存管理类

    @Autowired
    private UserCacheManager userCacheManager; // 用户缓存管理类

    @Autowired
    private UserExamMapper userExamMapper; // 用户竞赛数据访问接口

    /**
     * 查询竞赛列表。
     *
     * @param examQueryDTO 竞赛查询条件
     * @return 竞赛VO列表
     */
    @Override
    public List<ExamVO> list(ExamQueryDTO examQueryDTO) {
        PageHelper.startPage(examQueryDTO.getPageNum(), examQueryDTO.getPageSize());
        return examMapper.selectExamList(examQueryDTO);
    }

    /**
     * 从 Redis 中查询竞赛列表。
     *
     * @param examQueryDTO 竞赛查询条件
     * @return 分页数据
     */
    @Override
    public TableDataInfo redisList(ExamQueryDTO examQueryDTO) {
        // 从 Redis 中获取竞赛列表的大小
        Long total = examCacheManager.getListSize(examQueryDTO.getType(), null);
        List<ExamVO> examVOList;
        if (total == null || total <= 0) {
            // 如果 Redis 中没有数据，从数据库中查询并刷新缓存
            examVOList = list(examQueryDTO);
            examCacheManager.refreshCache(examQueryDTO.getType(), null);
            total = new PageInfo<>(examVOList).getTotal();
        } else {
            // 从 Redis 中获取竞赛列表
            examVOList = examCacheManager.getExamVOList(examQueryDTO, null);
            total = examCacheManager.getListSize(examQueryDTO.getType(), null);
        }

        // 检查获取的竞赛列表是否为空
        if (CollectionUtil.isEmpty(examVOList)) {
            return TableDataInfo.empty();
        }

        // 组装竞赛VO列表
        assembleExamVOList(examVOList);
        return TableDataInfo.success(examVOList, total);
    }

    /**
     * 查询竞赛排名列表。
     *
     * @param examRankDTO 竞赛排名查询条件
     * @return 分页数据
     */
    @Override
    public TableDataInfo rankList(ExamRankDTO examRankDTO) {
        // 从 Redis 中获取竞赛排名列表的大小
        Long total = examCacheManager.getRankListSize(examRankDTO.getExamId());
        List<ExamRankVO> examRankVOList;
        if (total == null || total <= 0) {
            // 如果 Redis 中没有数据，从数据库中查询并刷新缓存
            PageHelper.startPage(examRankDTO.getPageNum(), examRankDTO.getPageSize());
            examRankVOList = userExamMapper.selectExamRankList(examRankDTO.getExamId());
            examCacheManager.refreshExamRankCache(examRankDTO.getExamId());
            total = new PageInfo<>(examRankVOList).getTotal();
        } else {
            // 从 Redis 中获取竞赛排名列表
            examRankVOList = examCacheManager.getExamRankList(examRankDTO);
        }
        if (CollectionUtil.isEmpty(examRankVOList)) {
            return TableDataInfo.empty();
        }
        assembleExamRankVOList(examRankVOList);
        return TableDataInfo.success(examRankVOList, total);
    }

    /**
     * 获取竞赛的第一个题目ID。
     *
     * @param examId 竞赛ID
     * @return 第一个题目ID
     */
    @Override
    public String getFirstQuestion(Long examId) {
        checkAndRefresh(examId);
        return examCacheManager.getFirstQuestion(examId).toString();
    }

    /**
     * 获取当前题目的上一个题目ID。
     *
     * @param examId     竞赛ID
     * @param questionId 当前题目ID
     * @return 上一个题目ID
     */
    @Override
    public String preQuestion(Long examId, Long questionId) {
        checkAndRefresh(examId);
        return examCacheManager.preQuestion(examId, questionId).toString();
    }

    /**
     * 获取当前题目的下一个题目ID。
     *
     * @param examId     竞赛ID
     * @param questionId 当前题目ID
     * @return 下一个题目ID
     */
    @Override
    public String nextQuestion(Long examId, Long questionId) {
        checkAndRefresh(examId);
        return examCacheManager.nextQuestion(examId, questionId).toString();
    }

    /**
     * 组装竞赛VO列表，标记用户是否已参与竞赛。
     *
     * @param examVOList 竞赛VO列表
     */
    private void assembleExamVOList(List<ExamVO> examVOList) {
        // 从线程上下文中获取当前用户的ID
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);

        // 获取用户参与的竞赛ID列表
        List<Long> userExamIdList = examCacheManager.getAllUserExamList(userId);

        // 如果用户没有参与任何竞赛，直接返回
        if (CollectionUtil.isEmpty(userExamIdList)) {
            return;
        }

        // 遍历竞赛VO列表
        for (ExamVO examVO : examVOList) {
            // 检查用户是否已参与当前竞赛
            if (userExamIdList.contains(examVO.getExamId())) {
                // 如果用户已参与，设置 enter 标志为 true
                examVO.setEnter(true);
            }
        }
    }

    /**
     * 组装竞赛排名VO列表，设置用户昵称。
     *
     * @param examRankVOList 竞赛排名VO列表
     */
    private void assembleExamRankVOList(List<ExamRankVO> examRankVOList) {
        if (CollectionUtil.isEmpty(examRankVOList)) {
            return;
        }
        for (ExamRankVO examRankVO : examRankVOList) {
            Long userId = examRankVO.getUserId();
            UserVO user = userCacheManager.getUserById(userId);
            examRankVO.setNickName(user.getNickName()); // 设置用户昵称
        }
    }

    /**
     * 检查并刷新竞赛题目缓存。
     *
     * @param examId 竞赛ID
     */
    private void checkAndRefresh(Long examId) {
        Long listSize = examCacheManager.getExamQuestionListSize(examId);
        if (listSize == null || listSize <= 0) {
            examCacheManager.refreshExamQuestionCache(examId); // 刷新竞赛题目缓存
        }
    }
}
